package main

import (
	"fmt"
	"math/rand"
	"sort"
)

func main() {
	// 作业1
	exercise_1()
	// 问题1：请问s1、s2内各有什么元素？
	// ---- s1内的元素是 [0 0 0]，s2内的元素是[0 0 0 1]
	// 问题2：s1修改一个元素会影响s2吗？s2修改一个元素会影响s1吗？
	// ---- s1修改一个元素会影响s2，s2修改一个元素可能会影响s1，也可能不影响s1，要看索引的位置
	// ---- 原因：s1和s2共用同一个底层数组
	// 问题3：s2再增加一个元素会怎么样？
	// ---- s2再增加一个元素后，底层数组会扩容，在内存的另外一片区域开辟一个新的空间 /
	// ---- s2的容量为8，长度为5，标头值的指针指向新的底层数组地址
	// 程序运行结果：
	// []int [0 0 0] 0xc000008078 0xc0000181c0
	// []int [0 0 0 1] 0xc0000080a8 0xc0000181c0
	// []int [0 100 0] 0xc000008078 0xc0000181c0
	// []int [0 200 0 1] 0xc0000080a8 0xc0000181c0
	// []int [0 200 0 300] 0xc0000080a8 0xc0000181c0
	// s2再增加一个元素后的长度和容量分别是：5 8
	// []int [0 200 0 300 4000] 0xc0000080a8 0xc0000162c0
	fmt.Println("-------------------------------------------------------")

	// 作业2：有一个数组[1,4,9,16,2.5,10,15]，生成一个新切片，要求新切片元素是数组相邻2项的和
	exercise_2()
	fmt.Println("-------------------------------------------------------")

	// 作业3：数字重复统计
	// ---- 随机产生100个整数
	// ---- 数字的范围[-100,100]
	// ---- 降序输出这些生成的数字并打印其重复的次数
	exercise_3()

	// 作业4：简述线性数据结构和哈希表优劣
	// -- 线性数据结构
	// -- 优势：结构简单,分为顺序表和链表。适合数据量小，查询量小的情况
	// ------  顺序表，查找快，通过索引直接查找
	// ------  链表，插入快，删除快
	// ------  查询的时间复杂度，顺序表是O(1)，链表是O(n)
	// ------  增删的时间复杂度，顺序表是O(n)，链表是O(1)
	// -- 劣势：链表查找慢，顺序表增删慢，不适合大量数据存储情况。
	// ----------------------------------------------------------------------------------
	// -- 哈希表
	// -- 优势：插入、查询和删除都可以认为是O(1)的时间复杂度（无冲突）。适用于大量数据存储。
	// -- 劣势：有冲突的情况下就会出现性能问题，需要散列函数的设计要求，也比较消耗内存。

}

func exercise_1() {
	s1 := make([]int, 3, 4)
	fmt.Printf("%T %[1]v %p %p\n", s1, &s1, &s1[0]) // 打印s1的元素类型和值
	s2 := append(s1, 1)
	fmt.Printf("%T %[1]v %p %p\n", s2, &s2, &s2[0]) // 打印s2的元素类型和值
	// 修改s1的一个元素
	s1[1] = 100
	fmt.Printf("%T %[1]v %p %p\n", s1, &s1, &s1[0])
	// 修改s2的一个元素，索引序号和s1相同
	s2[1] = 200
	fmt.Printf("%T %[1]v %p %p\n", s2, &s2, &s2[0])
	// 修改s2的一个元素，索引序号和s1不同
	s2[3] = 300
	fmt.Printf("%T %[1]v %p %p\n", s2, &s2, &s2[0])
	// s2增加一个元素
	s2 = append(s2, 4000)
	fmt.Printf("s2再增加一个元素后的长度和容量分别是：%d %d\n", len(s2), cap(s2))
	fmt.Printf("%T %[1]v %p %p\n", s2, &s2, &s2[0])
}

func exercise_2() {
	array_1 := [...]int{1, 4, 9, 16, 2, 5, 10, 15}
	slice_1 := make([]int, 7)
	for i := 0; i < len(array_1)-1; i++ {
		slice_1[i] = array_1[i] + array_1[i+1]
	}
	fmt.Printf("%+v\n", array_1)
	fmt.Printf("%+v\n", slice_1)
}

func exercise_3() {
	// 声明一个长度为100的数组，初始化值都为0
	array_1 := [100]int{}
	for i := 0; i < len(array_1); i++ {
		// 随机生成100个整数，数字的范围[-100,100]
		array_1[i] = rand.Intn(200) - 100
	}
	fmt.Printf("%+v\n", array_1)

	// 将上面数组元素值放到一个map的key中，去重。map的value初值都设置为0，作为统计次数的初值
	map_1 := make(map[int]int)
	for i := 0; i < len(array_1); i++ {
		map_1[array_1[i]] = 0
	}

	// 统计随机数产生的次数，修改map相应的key中的value值，此时value值是去重过的随机数的生成次数
	for i := 0; i < len(array_1); i++ {
		if _, ok := map_1[array_1[i]]; ok {
			map_1[array_1[i]] = map_1[array_1[i]] + 1
		}
	}

	// 取出map中所有的key到一个slice中
	slice_1 := []int{}
	for i := range map_1 {
		slice_1 = append(slice_1, i)
	}

	// 将slice_1降序排列
	sort.Sort(sort.Reverse(sort.IntSlice(slice_1)))

	// 降序输出上面生成的数字并打印重复次数
	for i := 0; i < len(slice_1); i++ {
		fmt.Printf("%-4d 重复次数：%d\n", slice_1[i], map_1[slice_1[i]])
	}
}
